package com.china.produce.netty.learning.client;

import com.china.produce.netty.learning.message.*;
import com.china.produce.netty.learning.protocol.MessageCodecSharable;
import com.china.produce.netty.learning.protocol.ProcotolFrameDecoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @ClassName
 * @Author niujie
 * @Version
 * @Description
 * @CreateTime 2024/9/16
 */
public class ChatGroupClient {

    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup group = new NioEventLoopGroup();
        LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.DEBUG);
        MessageCodecSharable MESSAGE_CODEC = new MessageCodecSharable();

        // 计数器
        CountDownLatch WAIT_FOR_LOGIN = new CountDownLatch(1);
        // 检测登陆变量
        AtomicBoolean LOGIN = new AtomicBoolean(false);
        // 检测断开连接变量
        AtomicBoolean EXIT = new AtomicBoolean(false);
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.group(group);
            bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                                  @Override
                                  protected void initChannel(SocketChannel ch) throws Exception {
                                    ch.pipeline().addLast(new ProcotolFrameDecoder());
                                    ch.pipeline().addLast(MESSAGE_CODEC);
                                    ch.pipeline().addLast(LOGGING_HANDLER);
                                    ch.pipeline().addLast(new IdleStateHandler(0, 15, 0));
                                    ch.pipeline().addLast(new ChannelDuplexHandler() {
                                        @Override
                                        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                                            if (evt instanceof IdleStateEvent) {
                                                IdleStateEvent event = (IdleStateEvent) evt;
                                                // 触发读事件
                                                if (event.state() == IdleState.WRITER_IDLE) {
                                                    System.out.println("已经15s没有写入数据!");
                                                    ChannelFuture channelFuture = ctx.channel().writeAndFlush(new PingMessage());
                                                    channelFuture.addListener((ChannelFuture cf) -> {
                                                        System.out.println("====" + cf.isSuccess() + "====");
                                                    });
                                                }
                                            }
                                        }
                                    });
                                    ch.pipeline().addLast("login response handler", new SimpleChannelInboundHandler<LoginResponseMessage>() {
                                        @Override
                                        protected void channelRead0(ChannelHandlerContext ctx, LoginResponseMessage msg) throws Exception {
                                            if (msg.isSuccess()) {
                                                LOGIN.set(true);
                                            }
                                            WAIT_FOR_LOGIN.countDown();
                                        }
                                    });
                                    ch.pipeline().addLast("chat request handler", new SimpleChannelInboundHandler<ChatResponseMessage>() {
                                        @Override
                                        protected void channelRead0(ChannelHandlerContext ctx, ChatResponseMessage msg) throws Exception {
                                            System.out.println("receive msg from server " + msg);
                                        }
                                    });
                                    ch.pipeline().addLast("client handler", new ChannelInboundHandlerAdapter() {
                                        // 在连接断开时触发
                                        @Override
                                        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                                            System.out.println("连接已断开，请按任意键退出...");
                                            EXIT.set(true);
                                        }

                                        // 在出现异常时触发
                                        @Override
                                        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                            System.out.println("连接已断开，请按任意键退出...，异常信息");
                                            EXIT.set(true);
                                        }

                                        @Override
                                        public void channelActive(ChannelHandlerContext ctx){
                                            new Thread(() -> {
                                                Scanner scanner = new Scanner(System.in);
                                                System.out.println("请输入用户名：");
                                                String username = scanner.nextLine();
                                                if (EXIT.get()) {
                                                    return;
                                                }
                                                System.out.println("请输入密码：");
                                                String password = scanner.nextLine();
                                                if (EXIT.get()) {
                                                    return;
                                                }
                                                LoginRequestMessage message = new LoginRequestMessage(username, password);
                                                ctx.channel().writeAndFlush(message);
                                                try {
                                                    WAIT_FOR_LOGIN.await();
                                                } catch (InterruptedException e) {
                                                    e.printStackTrace();
                                                }
                                                if (!LOGIN.get()) {
                                                    System.out.println("登录失败");
                                                    ctx.channel().close();
                                                    return;
                                                }
                                                System.out.println("登录成功");

                                                while (true) {
                                                    String command = scanner.nextLine();
                                                    String[] split = command.split(" ");
                                                    switch (split[0]) {
                                                        case "send":
                                                            ctx.writeAndFlush(new ChatRequestMessage(username, split[1], split[2]));
                                                            break;
                                                        case "gcreate":
                                                            HashSet<String> users = new HashSet<>(Arrays.asList(split[2].split(",")));
                                                            users.add(username);
                                                            ctx.writeAndFlush(new GroupCreateRequestMessage(split[1], users));
                                                            break;
                                                        case "gsend":
                                                            ctx.writeAndFlush(new GroupChatRequestMessage(username, split[1], split[2]));
                                                            break;
                                                    }
                                                }
                                            }, "system in").start();
                                        }
                                    });
                                  }
                              });
            Channel channel = bootstrap.connect("localhost", 8081).sync().channel();
            channel.closeFuture().sync();
        }finally {

            group.shutdownGracefully();
        }
    }
}
